<template>
  <div v-show="!showAlgo">
    <!-- 上传图片 -->
    <n-upload
      ref="uploadRef"
      :action="uploadUrl"
      :max="1"
      :with-credentials="true"
      :custom-request="uploadRequest"
      class="uploads"
      @before-upload="beforeUpload"
    >
      <n-upload-dragger style="width: 500px">
        <div style="margin-bottom: 12px">
          <n-icon size="48" :depth="3">
            <upload-icon />
          </n-icon>
        </div>
        <n-text style="font-size: 16px" :depth="3"
          >Drop File Here or Clik to Upload</n-text
        >
      </n-upload-dragger>
    </n-upload>
    <n-h2>
      <n-text>Examples</n-text>
    </n-h2>
    <n-data-table
      :columns="createColumns({ choose })"
      :data="exampleData.data"
      :pagination="false"
      :bordered="false"
    />
  </div>
  <div v-show="showAlgo">
    <n-image-group>
      <n-space justify="space-around">
        <div class="img-container">
          <div class="img-edit" id="img-box">
            <img width="450" :src="sourceImg" id="source-img" />
          </div>
          <n-h3>
            <n-text :depth="3" :strong="true">Input</n-text>
            <n-button
              quaternary
              circle
              type="success"
              tag="a"
              :href="
                sourceImg + '?response-content-type=application/octet-stream'
              "
              download
            >
              <template #icon>
                <n-icon>
                  <download-icon />
                </n-icon>
              </template>
            </n-button>
            <n-button quaternary circle type="success" @click="undo">
              <template #icon>
                <n-icon>
                  <undo-icon />
                </n-icon>
              </template>
            </n-button>
            <n-button
              quaternary
              circle
              type="success"
              @click="refreshSelection"
            >
              <template #icon>
                <n-icon>
                  <refresh-icon />
                </n-icon>
              </template>
            </n-button>
          </n-h3>
        </div>
        <div class="img-container">
          <n-image width="450" :src="targetImg" :fallback-src="targetImg" />
          <n-h3 v-show="targetImg !== '/assets/example/fallback.jpg'">
            <n-text :depth="3" :strong="true">Output</n-text>
            <n-button
              quaternary
              circle
              type="success"
              tag="a"
              :href="
                targetImg + '?response-content-type=application/octet-stream'
              "
              download
            >
              <template #icon>
                <n-icon>
                  <download-icon />
                </n-icon>
              </template>
            </n-button>
          </n-h3>
        </div>
      </n-space>
    </n-image-group>
    <n-space justify="end">
      <n-button type="tertiary" @click="handleClear" :disabled="isExecuting"
        >Clear</n-button
      >
      <n-button type="primary" @click="handleExecute" :disabled="isExecuting"
        >Execute</n-button
      >
    </n-space>
  </div>
</template>

<script setup>
import {
  CloudUploadOutline as UploadIcon,
  DownloadOutline as DownloadIcon,
  Refresh as RefreshIcon,
  ArrowBack as UndoIcon
} from '@vicons/ionicons5'
import { useMessage, useLoadingBar, NImage, NButton } from 'naive-ui'
import axios from 'axios'

const uploadUrl = 'http://47.93.249.243:8000/file/upload/'

const executeUrl = 'http://47.93.249.243:8000/file/execute/'

const message = useMessage()

onMounted(() => {
  handleClear()
})

onUpdated(() => {
  init()
})

class Coord {
  constructor(x, y, width, height) {
    this.point = {
      x: x,
      y: y
    }
    this.width = width
    this.height = height
  }
}

const init = () => {
  let oBox = document.getElementById('img-box')
  let offset = getOffset(oBox)
  let coord = null
  //鼠标按下，获取初始点
  oBox.onmousedown = (ev) => {
    ev = window.event || ev
    let img = document.getElementById('source-img')
    let scale = img.naturalWidth / img.width
    //1.获取按下的点
    let x1 = ev.clientX - offset.left
    let y1 = ev.clientY - offset.top
    //2.创建div
    let oDiv = document.createElement('div')
    coord = new Coord(0, 0, 0, 0)
    oBox.appendChild(oDiv)
    oBox.onmousemove = (ev) => {
      ev = window.event || ev
      let x2 = ev.clientX - offset.left
      let y2 = ev.clientY - offset.top
      x2 = x2 > img.offsetWidth ? img.offsetWidth : x2
      y2 = y2 > img.offsetHeight ? img.offsetHeight : y2
      //3.设置div的样式
      coord.point.x = (x2 > x1 ? x1 : x2) * scale
      coord.point.y = (y2 > y1 ? y1 : y2) * scale
      coord.width = Math.abs(x2 - x1) * scale
      coord.height = Math.abs(y2 - y1) * scale

      oDiv.style.left = (x2 > x1 ? x1 : x2) + 'px'
      oDiv.style.top = (y2 > y1 ? y1 : y2) + 'px'
      oDiv.style.width = Math.abs(x2 - x1) + 'px'
      oDiv.style.height = Math.abs(y2 - y1) + 'px'
    }
    coords.value.push(coord)
    return false //解除在划动过程中鼠标样式改变的BUG
  }
  //在鼠标抬起后终止onmousemove事件
  document.onmouseup = function () {
    oBox.onmousemove = null
  }
}

const getOffset = (box) => {
  const offset = {
    left: 0,
    top: 0
  }
  while (box != null) {
    offset.left += box.offsetLeft
    offset.top += box.offsetTop
    box = box.offsetParent
  }
  return offset
}

const coords = ref([])

const refreshSelection = () => {
  coords.value.length = 0
  let oBox = document.getElementById('img-box')
  let selections = oBox.querySelectorAll('div')
  selections.forEach((item) => {
    oBox.removeChild(item)
  })
}

const undo = () => {
  if (coords.value.length > 0) {
    coords.value.pop()
    let oBox = document.getElementById('img-box')
    let selections = oBox.querySelectorAll('div')
    console.log(selections)
    oBox.removeChild(selections[selections.length - 1])
  }
}

// 展示算法
const showAlgo = ref(false)

const uploadRef = ref()

// 原图片
const sourceImg = ref('')
// 目标图片
const targetImg = ref('/assets/example/fallback.jpg')

// 文件类型检测
const beforeUpload = (data) => {
  if (
    data.file.file?.type !== 'image/png' &&
    data.file.file?.type !== 'image/jpeg'
  ) {
    message.error('Only PNG and JPEG image files can be uploaded')
    return false
  }
  return true
}

// 上传请求
const uploadRequest = ({
  file,
  data,
  headers,
  withCredentials,
  action,
  onFinish,
  onError,
  onProgress
}) => {
  const formData = new FormData()
  formData.append('file', file.file)
  axios({
    url: action,
    method: 'POST',
    headers: { 'Content-Type': 'multipart/form-data' },
    data: formData,
    timeout: 0,
    onUploadProgress: ({ loaded, total }) => {
      onProgress({ percent: Math.ceil((loaded / total) * 100) })
    }
  })
    .then((res) => {
      if (res.data.success) {
        message.success('Successfully uploaded')
        showAlgo.value = true
        sourceImg.value = res.data.url
      }
    })
    .catch(() => {
      message.error('Image upload failed, please try again')
    })
}

const loadingBar = useLoadingBar()

// 清空图片回调
const handleClear = () => {
  sourceImg.value = ''
  targetImg.value = '/assets/example/fallback.jpg'
  refreshSelection()
  uploadRef.value.clear()
  showAlgo.value = false
}

const isExecuting = ref(false)

// 执行回调
const handleExecute = () => {
  loadingBar.start()
  isExecuting.value = true
  axios({
    url: executeUrl,
    method: 'POST',
    data: {
      url: sourceImg.value,
      coords: coords.value
    },
    timeout: 0
  })
    .then((res) => {
      if (res.data.success) {
        message.success('Successful execution')
        targetImg.value = res.data.url
        loadingBar.finish()
      }
    })
    .catch(() => {
      message.error('Execution failed, please try again')
      loadingBar.error()
    })
  isExecuting.value = false
}

const choose = (url) => {
  sourceImg.value = url
  targetImg.value = '/assets/example/fallback.jpg'
  showAlgo.value = true
}

// 创建表头
const createColumns = ({ choose }) => {
  return [
    {
      title: 'Image',
      key: 'url',
      render(row) {
        return h(NImage, {
          src: row.url,
          width: '300'
        })
      }
    },
    {
      title: 'Action',
      key: 'actions',
      align: 'center',
      width: '300',
      render(row) {
        return h(
          NButton,
          {
            strong: true,
            size: 'small',
            type: 'primary',
            onClick: () => choose(row.url)
          },
          { default: () => 'Choose' }
        )
      }
    }
  ]
}

// 示例数据
const exampleData = {
  data: [{ url: '/assets/example/egimg1.png' }]
}
</script>

<style scoped>
.uploads {
  text-align: center;
}

.img-container {
  display: flex;
  flex-direction: column;
  text-align: center;
}

.img-edit {
  position: relative;
}

.img-edit >>> div {
  position: absolute;
  border: 3px dashed #18a058;
  top: 40px;
  left: 50px;
}
</style>
